﻿using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Security.Cryptography;

using Google.GData.Client;

using SBPweb.Forge.Cryptography;
using SBPweb.Forge.Web;

using SBPweb.GoogleDataAPI.Shared.Contracts;

namespace SBPweb.GoogleDataAPI.Server.Services
{

    public class ClientService : ClientService<Service, IClientService>
    {

        #region Constructor logic

        public ClientService()
            : base()
        {
        }

        #endregion

        #region Methods

        protected override Service CreateServiceInstance()
        {
            return new Service("gdata.sbpweb.hu");
        }

        protected internal override string GetCryptographycSalt(string extra)
        {
            return string.Format("B5EC3466-3B8E-4aac-B6A5-67686F532F0B-{0}", extra);
        }

        #endregion

    }

    public abstract class ClientService<TService, TContract> : 
        IClientService
        where TService : Service
        where TContract : IClientService
    {

        #region Protected fields

        protected string token;
        protected TService service;
        protected CustomCryptographyProvider crypter = new CustomCryptographyProvider();

        #endregion

        #region Constructor logic

        public ClientService()
        {
            service = CreateServiceInstance();
        }

        #endregion

        #region Methods

        #region Operations

        [OperationBehavior(
            TransactionScopeRequired = true
        )]
        public string Authenticate(string userName, string password)
        {
            string authToken;
            try
            {
                string decryptedPass = crypter.Decrypt<string>(password, GetCryptographycSalt(userName));
                service.setUserCredentials(userName, decryptedPass);
                authToken = service.QueryAuthenticationToken();

                StoreToken(authToken);

                return authToken;
            }
            catch (InvalidCredentialsException icex)
            {
            }
            catch (CryptographicException ex)
            {
            }
            return null;
        }

        #endregion

        #region Overridden

        protected abstract TService CreateServiceInstance();

        internal protected abstract string GetCryptographycSalt(string extra);

        internal protected string GetCryptographycSalt()
        {
            return GetCryptographycSalt(string.Empty);
        }

        #endregion

        #region Helper functions

        protected void StoreToken(string token)
        {
            SessionManager.Session.Put<string>(token, "GDataToken", token);
            this.token = token;
        }

        protected void FetchAndCheckToken()
        {
            string token;
            try
            {
                int i = OperationContext.Current.IncomingMessageHeaders.FindHeader("AuthToken", "SBPwebTech");
                token = OperationContext.Current.IncomingMessageHeaders.GetHeader<string>(i);
                this.token = SessionManager.Session.Get<string>(token, "GDataToken");
            }
            catch
            {
                throw new Exception("Token was not found!");
            }

            //SessionManager.Session.Put<string>(token, "GDataToken", token);
        }

        #endregion

        #endregion

    }

}